package math;

import utilities.Versionable;



public class Vector3D implements Versionable<Vector3D>
{
	
	public static final Vector3D X = new Vector3D(1,0,0) ;
	public static final Vector3D Y = new Vector3D(0,1,0) ;
	public static final Vector3D Z = new Vector3D(0,0,1) ;
	
	private double x;
	private double y;
	private double z;
	
	public Vector3D clone(){
		return new Vector3D(x,y,z);
	}
	
	public Vector3D(double x,double y,double z)
	{
		this.x = x;
		this.y = y;
		this.z = z;
		
		
	}
	public Vector3D(Vector3D v) {
		this.x = v.x;
		this.y = v.y;
		this.z = v.z;
	}
	/**
	 * 
	 * @return first value of the vector
	 */
	public double getX() 
	{
		return x;
	}
	/**
	 * 
	 * @param set the first value of the vector
	 */
	public void setX(double x) 
	{
		this.x = x;
	}
	
	/**
	 * 
	 * @return the second value of the vector
	 */
	public double getY()
	{
		return y;
	}
	
	/**
	 * 
	 * @return set the second value of the vector
	 */
	public void setY(double y)
	{
		this.y = y;
	}
	
	/**
	 * 
	 * @return the third value of the vector
	 */
	public double getZ()
	{
		return z;
	}
	/**
	 * 
	 * @return set the third value of the vector
	 */
	public void setZ(double z)
	{
		this.z = z;
	}
	/**
	 * 
	 * @return the squared length
	 */
	public double getSquaredlength()
	{
		return x*x + y*y+ z*z;
	}
	/**
	 * 
	 * @return the length
	 */
	public double getLength()
	{
		return Math.sqrt(this.getSquaredlength());
	}
	/**
	 * 
	 * @return the vertical angle in rad
	 */
	public double getTheta()
	{
		return Math.asin(z/getLength());
	}
	/**
	 * 
	 * @return the horizontal angle in rad
	 */
	public double getPhi()
	{
		if(getX()>=0)
		return Math.atan(y/x);
		else
		return Math.atan(y/x) + Math.PI;
		
	}
	
	/**
	 * 
	 * @param multiply the current vector by a
	 */
	public Vector3D add(Vector3D v){
		
		return new Vector3D(this.x + v.x, this.y + v.y , this.z + v.z);
		
	}
	
	public void thisAdd(Vector3D v){
		
		this.x += v.x;
		this.y += v.y;
		this.z += v.z;
		
	}
	public Vector3D remove(Vector3D v)
	{
		return new Vector3D(this.x - v.x, this.y-v.y , this.z-v.z);
	}
	public void thisRemove(Vector3D v)
	{
		this.x -= v.x;
		this.y -= v.y;
		this.z -= v.z;
	}
	
	public Vector3D add(double d, double e, int i)
	{
		return new Vector3D(this.x + d, this.y+e , this.z+ i);
	}
	
	
	public void thisTime(double a)
	{
		x= a*x;
		y= a*y;
		z= a*z;
	}
	/**
	 * 
	 * @param a a double
	 * @return a*this 
	 */
	public Vector3D time(double a)
	{
		return new Vector3D(a*x,a*y,a*z);
	}
	
	/**
	 * 
	 * @param make the cross product of this and v
	 */
	public void thisCross(Vector3D v)
	{
				x = y*v.z- z*v.y;	
				y = z*v.x- x*v.z;	
				z = x*v.y- y*v.x; 
	}
	/**
	 * 
	 * @param vector3D v 
	 * @return the cross product of this and v
	 */
	public Vector3D cross(Vector3D v)
	{
				return new Vector3D (y*v.z- z*v.y,
									 z*v.x- x*v.z,	
									 x*v.y- y*v.x	); 
	}
	/**
	 * 
	 * @param other Vector3D v
	 * @return the dotProduct
	 */
	public double dotProduct(Vector3D v)
	{
				return x * v.x+ y * v.y+ z * v.z;
	}
	
	public void normalise()
	{
		this.thisTime(1/this.getLength());
	}
	
	public Vector3D getNormal2D()
	{
		return new Vector3D(-y,x,0);
	}
	 public String toString()
	 {
		 return x+" "+y+" "+z;
	 }
	
	
}
